package org.fududu.oauth2;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableMap;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

/**
 * The default implementation of the {@code AuthzRequest}.
 *
 * @author Fuchun
 * @since 1.0
 */
public class DefaultAuthzRequest extends AbstractOAuth2Request implements AuthzRequest {

    private static final long serialVersionUID = 674966357127434439L;

    private String responseType;
    private String state;

    /**
     * Construct a new DefaultAuthzRequest.
     */
    public DefaultAuthzRequest() {
        super();
    }

    /**
     * Construct a new DefaultAuthzRequest, given a URL query string.
     *
     * @param queryString a URL query string
     */
    public DefaultAuthzRequest(String queryString) {
        super();
        this.queryString = queryString == null ? null : queryString.trim();
        parseQueryString();
    }

    /**
     * Construct a new DefaultAuthzRequest, given the parameters: responseType, clientId, redirectUri etc.
     *
     * @param responseType the response type string.
     * @param clientId the request client identifier.
     * @param redirectUri the request redirect uri.
     * @param scope the request access scope.
     * @param state the request custom state.
     */
    public DefaultAuthzRequest(String responseType, String clientId, String redirectUri, String scope, String state) {
        super(clientId, null, redirectUri, scope);
        this.responseType = responseType;
        this.state = state;
    }

    protected Map<String, String> parseQueryString() {
        Map<String, String> qsMap = super.parseQueryString();
        responseType = qsMap.get(OAuth2.RESPONSE_TYPE);
        state = qsMap.get(OAuth2.STATE);

        if (customParams != null && customParams.size() > 0) {
            customParams.clear();
        }

        for (Map.Entry<String, String> entry : qsMap.entrySet()) {
            if (OAuth2.AUTHZ_REQUEST_PARAMS.contains(entry.getKey())) {
                continue;
            }
            if (customParams == null) {
                customParams = new LinkedHashMap<>();
            }
            customParams.put(entry.getKey(), entry.getValue());
        }
        return qsMap;
    }

    @Override
    @JsonProperty(OAuth2.RESPONSE_TYPE)
    public String getResponseType() {
        return responseType;
    }

    public void setResponseType(String responseType) {
        this.responseType = responseType;
    }

    @Override
    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    @Override
    public String getQueryString() {
        return getQueryString(Collections.singletonList(OAuth2.CLIENT_SECRET));
    }

    @Override
    protected void addPrevParam(Map<String, String> keyValueMap) {
        keyValueMap.put(OAuth2.RESPONSE_TYPE, getResponseType());
    }

    @Override
    protected void addLastParam(Map<String, String> keyValueMap) {
        keyValueMap.put(OAuth2.STATE, getState());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof DefaultAuthzRequest)) return false;
        if (!super.equals(o)) return false;

        DefaultAuthzRequest that = (DefaultAuthzRequest) o;

        return Objects.equals(responseType, that.responseType) &&
                Objects.equals(state, that.state);
    }

    @Override
    public int hashCode() {
        int result = super.hashCode();
        result = 31 * result + (responseType != null ? responseType.hashCode() : 0);
        result = 31 * result + (state != null ? state.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return toStringHelper(ImmutableMap.of("responseType", getResponseType()),
                ImmutableMap.of("state", getState())).toString();
    }
}
